"""
CSPBuilder plugin

Copyright (c) 2008 Rune M. Friborg, runef@diku.dk.
See LICENSE.txt for licensing details (GPLv2).
"""

PLUGIN_NAME = "ForkNJoin"

import wx
import os
import base64

try:
	import cPickle as pickle
except:
	import pickle



from extensions import cspxml
from plugins.builder import *


class PluginForkNJoin(PluginBUILDER):
	
	def __init__(self, pluginManager):
		PluginBUILDER.__init__(self, pluginManager, PLUGIN_NAME)
		self.switchButton = None
		self.panel = None
		# pref menu
		self.server = ''
		self.cert =''
		self.key = ''
		self.passwd = ''
		self.vgrid = ''
		self.mig_script_path = ''
		
		self.home = os.getenv('USERPROFILE') or os.getenv('HOME')
		self.miguser_conf = self.home + '/.cspbuilder/miguser.conf'
		self.migprefs_conf = self.home + '/.cspbuilder/migprefs.conf'
		
		self._load_pref()		

	def create_send_to_grid_rcmenu(self, frame, menu, obj, menuid):
		
		if obj.plugin_attr.has_key('forkNJoin') and obj.plugin_attr['forkNJoin'] == 1:
			item = menu.AppendCheckItem(menuid, 'Send To MiG')			
			frame.Bind(wx.EVT_MENU, lambda event:self.send_to_grid_clicked(frame,event), id=menuid)
			if (obj.plugin_attr.has_key('sendToGrid') and obj.plugin_attr['sendToGrid'] == 1):
				item.Check(True)
			else:
				item.Check(False)
		
	def create_files_rcmenu(self, frame, menu, obj, menuid):
		if obj.plugin_attr.has_key('forkNJoin') and obj.plugin_attr['forkNJoin'] == 1:		
			confItem = menu.Append(menuid, 'MiG Files...')		
			if (obj.plugin_attr.has_key('sendToGrid') and obj.plugin_attr['sendToGrid'] == 1):
				frame.Bind(wx.EVT_MENU, lambda event:self.configure_files(frame, obj), id=menuid)
			else:
				confItem.Enable(False)

	def create_job_rcmenu(self, frame, menu, obj, menuid):

		if obj.plugin_attr.has_key('forkNJoin') and obj.plugin_attr['forkNJoin'] == 1:		
			confItem = menu.Append(menuid, 'MiG Job Settings...')		
			if (obj.plugin_attr.has_key('sendToGrid') and obj.plugin_attr['sendToGrid'] == 1):
				frame.Bind(wx.EVT_MENU, lambda event:self.configure_job(frame, obj), id=menuid)
			else:
				confItem.Enable(False)
		
	def send_to_grid_clicked(self, frame, event):
		obj = frame.selection[0]
		if (obj.plugin_attr.has_key('sendToGrid') and obj.plugin_attr['sendToGrid'] == 1):
			obj.plugin_attr['sendToGrid'] = 0
		else:
			obj.plugin_attr['sendToGrid'] = 1


	def _check_sendToGrid(self, val):
		if (val):
			return 1
		else:
			return 0
			
	# ==============================================================================
	# = Functions for configuring MiG jobs in detail. Such as CPUTIME, MEMORY etc. =
	# ==============================================================================
	def change_control_state(self,controls, state):
		for control in controls:
			control.Enable(state)
			
	def configure_job(self,frame, obj):
		# create a config tag if it doesn't exist
		if not obj.plugin_tags.has_key('migJobConfig'):
			obj.plugin_tags['migJobConfig'] = {}
			
		ptags = obj.plugin_tags['migJobConfig']
		
		dialog = wx.Dialog(frame, -1, 'Configure MiG Job', size=wx.Size(370, 450), style = wx.CLOSE_BOX | wx.WANTS_CHARS )
		win = wx.Panel(dialog, -1)
		
		settings_box = wx.StaticBox(win,-1,'MiG Job Settings')
		in_order_box = wx.StaticBox(win,-1,'Asynchronous Execution')
				
				
		in_order_sizer = wx.StaticBoxSizer(in_order_box, wx.VERTICAL)
		enable_async = wx.CheckBox(win,-1,'Enable asynchronous execution')

		io_grid_sizer = wx.FlexGridSizer(rows=3, cols=1, hgap=5, vgap=5)
		io_grid_sizer.Add(wx.StaticText(win,-1,'This will cause MiG-jobs to be run asynchronously \nout-of-order, but results will be delivered in-order.'),
						1, wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, 8)
		io_grid_sizer.Add(enable_async,1,flag=wx.ALIGN_CENTER_VERTICAL)
	
		
		if ptags.has_key('inOrderJobs'):
			num_mig_procs = int(ptags['inOrderJobs'])
		else:
			num_mig_procs = 1
		
		is_async = num_mig_procs > 1
		
		enable_async.SetValue(is_async)
		
		spin_ctrl = wx.SpinCtrl(win, size=(80,-1))
		text = wx.StaticText(win, -1, 'Maximum concurrent MiG-jobs:')
		
		check_state_func = lambda event: self.change_control_state([spin_ctrl,text], enable_async.GetValue())
		
		enable_async.Bind(wx.EVT_CHECKBOX, check_state_func)


		spin_ctrl.SetRange(2,10000)
		if num_mig_procs > 1:
			spin_ctrl.SetValue(num_mig_procs)
		
		spin_ctrl.Enable(is_async)
		text.Enable(is_async)
		
		vbox_in_order = wx.BoxSizer(wx.HORIZONTAL)
		vbox_in_order.Add(text,1,wx.ALIGN_CENTER_VERTICAL)
		vbox_in_order.Add(spin_ctrl,0,wx.ALIGN_CENTER_VERTICAL | wx.LEFT,5)
		io_grid_sizer.Add(vbox_in_order,1,flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
		
		io_grid_sizer.AddGrowableCol(0, 1)
		in_order_sizer.Add(io_grid_sizer, 1, wx.ALL, 0)

		#hbox = wx.BoxSizer(wx.HORIZONTAL)
		gridSizer = wx.FlexGridSizer(rows=6, cols=2, hgap=5, vgap=5)
		
		# cputime
		val = ''
		if ptags.has_key('cpuTime'):
			val = ptags['cpuTime']			
		gridSizer.Add(wx.StaticText(win,-1, 'CPU Time (seconds):', style=wx.TE_RIGHT),1)
		cpu_time_text = wx.TextCtrl(win, -1, val)
		gridSizer.Add(cpu_time_text,1, wx.EXPAND)	
		
		# cpucount
		val = ''
		if ptags.has_key('cpuCount'):
			val = ptags['cpuCount']
		gridSizer.Add(wx.StaticText(win,-1, 'CPU Count:'),1)
		cpu_count_text = wx.TextCtrl(win, -1, val)
		gridSizer.Add(cpu_count_text,1, wx.EXPAND)	
		
		# nodecount
		val = ''
		if ptags.has_key('nodeCount'):
			val = ptags['nodeCount']
		gridSizer.Add(wx.StaticText(win,-1, 'Node Count:'),1)
		node_count_text = wx.TextCtrl(win, -1, val)
		gridSizer.Add(node_count_text,1, wx.EXPAND)	
		
		# memory
		val = ''
		if ptags.has_key('memory'):
			val = ptags['memory']
		gridSizer.Add(wx.StaticText(win,-1, 'Memory (MB):'),1)
		memory_text = wx.TextCtrl(win, -1, val)
		gridSizer.Add(memory_text,1, wx.EXPAND)	
		
		# disk
		val = ''
		if ptags.has_key('disk'):
			val = ptags['disk']
		gridSizer.Add(wx.StaticText(win,-1, 'Disk (GB):'),1)
		disk_text = wx.TextCtrl(win, -1, val)
		gridSizer.Add(disk_text,1, wx.EXPAND)	
		
		# architecture
		val = ''
		if ptags.has_key('architecture'):
			val = ptags['architecture']		
		gridSizer.Add(wx.StaticText(win,-1, 'Architecture:'),1)

		archs = ['','X86','AMD64','IA64','SPARC','SPARC64','ITANIUM','SUNU4','SPARC-T1', 'PS3', 'CELL']

		archs_box = wx.ComboBox(win, -1, choices=archs, 
							style=wx.CB_READONLY)		
		if val in archs:
			archs_box.SetValue(val)
		gridSizer.Add(archs_box,1, wx.EXPAND)
		
		# Buttons
		
		
		#gridSizer.Add(wx.StaticText(win,-1, ''),1)
		#gridSizer.Add(button_box,1,wx.ALIGN_RIGHT)	
		gridSizer.AddGrowableCol(1, 1)
		

				
		settings_sizer = wx.StaticBoxSizer(settings_box)
		settings_sizer.Add(gridSizer, 1, wx.ALL | wx.EXPAND, 0)
		
		button_box = wx.BoxSizer(wx.HORIZONTAL)
		button_box.Add(wx.Button(win, wx.ID_OK, 'Ok'), 1, wx.ALIGN_RIGHT)
		button_box.Add(wx.Button(win, wx.ID_CANCEL, 'Cancel'), 1, wx.ALIGN_RIGHT| wx.LEFT,5)		
		
		vbox = wx.BoxSizer(wx.VERTICAL)					
		vbox.Add(in_order_sizer, 0, wx.ALL | wx.EXPAND, 10)					
		vbox.Add(settings_sizer, 0,wx.ALL |wx.EXPAND, 10)		
		vbox.Add(button_box, 0,wx.ALL | wx.ALIGN_RIGHT, 10)	
		
		win.SetSizer(vbox)
		win.SetAutoLayout(True)
		dialog.Centre()
		
		done = False
		while not done:
			if dialog.ShowModal() == wx.ID_OK:
				tag = obj.plugin_tags['migJobConfig']
			
				success = True
				success &= self.set_int_config_value(cpu_time_text.GetValue().strip(),tag,'cpuTime')
				success &= self.set_int_config_value(cpu_count_text.GetValue().strip(),tag,'cpuCount')
				success &= self.set_int_config_value(node_count_text.GetValue().strip(),tag,'nodeCount')
				success &= self.set_int_config_value(memory_text.GetValue().strip(),tag,'memory')
				success &= self.set_int_config_value(disk_text.GetValue().strip(),tag,'disk')
				
				arch = archs_box.GetValue().strip()
				if arch != '':
					tag['architecture'] = arch
				elif tag.has_key('architecture'):
					del tag['architecture']
				
				if enable_async.GetValue():
					number_procs = spin_ctrl.GetValue()
					tag['inOrderJobs'] = str(number_procs)
				elif tag.has_key('inOrderJobs'):
					del tag['inOrderJobs']
				
				if not success:
					mess = wx.MessageDialog(frame, 'Error in input', 'Error', wx.OK | wx.ICON_ERROR)
					mess.ShowModal()
					mess.Destroy()
				else:
					done = True
			else:
				done = True

				
		dialog.Destroy()
	
	def set_int_config_value(self, text, tag, dest_attr):
		if text != '':
			# user entered something
			try:
				val = int(text)
				if val > 0:
					tag[dest_attr] = str(val)
			except:
				return False
		elif tag.has_key(dest_attr):
			# user entered nothing or white space.
			# we delete tag if exists.
			del tag[dest_attr]
			
		return True
		
	# ============================================================
	# = Functions for adding input and output files for MiG jobs =
	# ============================================================
	
	def locate_file_dialog(self, frame, target_text_ctrl, is_output=False):
		if is_output:
			mode_flags = wx.SAVE | wx.OVERWRITE_PROMPT
			title = 'Select Output File Destination'
		else:
			mode_flags = wx.OPEN
			title = 'Locate Input File'
		
		curDir = os.getcwd()
		fileName = wx.FileSelector(title, 
									default_path=curDir,
									flags = mode_flags)
		if fileName == "": 
			return # User cancelled.
		fileName = os.path.join(os.getcwd(), fileName)
		target_text_ctrl.SetValue(fileName)
		os.chdir(curDir)
			
	def add_or_edit_file(self, frame, local_path=None, remote_path=None, is_output=False):
		if local_path == None or remote_path == None:
			title = 'Add'
			local_path = ''
			remote_path = ''
		else:
			title = 'Edit'
		
		if is_output:
			title += ' Output '
		else:
			title += ' Input '
		
		title += 'File'
			
		dialog = wx.Dialog(frame, -1, title, size=wx.Size(550, 150), style = wx.DEFAULT_FRAME_STYLE | wx.WANTS_CHARS )
		win = wx.Panel(dialog, -1)
		hbox = wx.BoxSizer(wx.HORIZONTAL)
		gridSizer = wx.FlexGridSizer(rows=3, cols=3, hgap=5, vgap=5)
		browse_button = wx.Button(win,-1, "Browse...")
		browse_button.Bind(wx.EVT_BUTTON,lambda event:self.locate_file_dialog(frame,local_text,is_output))
		
		if is_output:
			remote_text =wx.TextCtrl(win, -1, remote_path)
			local_text = wx.TextCtrl(win, -1, local_path)			
			gridSizer.Add(wx.StaticText(win,-1, 'Remote Path:'),1,wx.ALIGN_CENTER_VERTICAL)
			gridSizer.Add(remote_text, 1, wx.EXPAND)
			gridSizer.Add(wx.StaticText(win,-1, ''),1)
			gridSizer.Add(wx.StaticText(win,-1, 'Local Path:'),1,wx.ALIGN_CENTER_VERTICAL)
			gridSizer.Add(local_text, 1, wx.EXPAND)
			gridSizer.Add(browse_button)
		else:		
			local_text = wx.TextCtrl(win, -1, local_path)
			remote_text =wx.TextCtrl(win, -1, remote_path)			
			gridSizer.Add(wx.StaticText(win,-1, 'Local Path:'),1,wx.ALIGN_CENTER_VERTICAL)
			gridSizer.Add(local_text, 1, wx.EXPAND)
			gridSizer.Add(browse_button)		
			gridSizer.Add(wx.StaticText(win,-1, 'Remote Path:'),1,wx.ALIGN_CENTER_VERTICAL)
			gridSizer.Add(remote_text, 1, wx.EXPAND)
			gridSizer.Add(wx.StaticText(win,-1, ''),1)
			
		gridSizer.Add(wx.StaticText(win,-1, ''),1)
		gridSizer.Add(wx.StaticText(win,-1, ''),1)
		# TODO add cancel button
		gridSizer.Add(wx.Button(win, wx.ID_OK, "Ok"), 1, wx.ALIGN_RIGHT)		
		
		gridSizer.AddGrowableCol(1, 1)
		hbox.Add(gridSizer, 1, wx.ALL | wx.EXPAND, 15)
		win.SetSizer(hbox)
		win.SetAutoLayout(True)
		dialog.Centre()
		
		if dialog.ShowModal() == wx.ID_OK:
			local_path = local_text.GetValue()
			remote_path = remote_text.GetValue()
		dialog.Destroy()
		self._save_pref()
		return (local_path,remote_path)

	def configure_files(self, frame, obj):
		dialog = wx.Dialog(frame, -1, 'Configure MiG Files', size=wx.Size(500, 500), style = wx.DEFAULT_FRAME_STYLE | wx.WANTS_CHARS )
		win = wx.Panel(dialog, -1)

		sizer = wx.BoxSizer(wx.VERTICAL) #wx.GridBagSizer(4, 4)

		text1 = wx.StaticText(win, -1, 'Input files')
		sizer.Add(text1, flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)

		self.input_file_list = wx.ListView(win, -1, size=wx.Size(490, 150), style=wx.LC_REPORT | wx.RAISED_BORDER)	
		self.input_file_list.InsertColumn(0,'Local path', width=245)
		self.input_file_list.InsertColumn(1,'Remote path (relative)', width=245)

		sizer.Add(self.input_file_list, flag=wx.EXPAND | wx.ALL |  wx.ALIGN_RIGHT, border=5)

		# input file buttons		
		box1 = wx.BoxSizer(wx.HORIZONTAL)		

		self.add_input = wx.Button(win, -1, "Add...")
		self.add_input.Bind(wx.EVT_BUTTON, lambda event:self.add_input_file(win,obj)) 

		self.rem_input = wx.Button(win, -1, "Remove")
		self.rem_input.Disable()
		self.rem_input.Bind(wx.EVT_BUTTON, lambda event:self.remove_input_file(win,obj)) 

		self.edit_input = wx.Button(win, -1, "Edit...")	
		self.edit_input.Disable()
		self.edit_input.Bind(wx.EVT_BUTTON, lambda event:self.edit_input_file(win,obj)) 

		self.input_file_list.Bind(wx.EVT_LIST_ITEM_SELECTED, lambda event:self.input_item_selected(frame, event))
		self.input_file_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, lambda event:self.input_item_deselected(frame, event))	

		box1.Add(self.add_input, flag=wx.ALL, border=5)
		box1.Add(self.rem_input, flag=wx.ALL, border=5 )	
		box1.Add(self.edit_input, flag=wx.ALL, border=5 )
		sizer.Add(box1,flag=wx.ALIGN_RIGHT)

		text2 = wx.StaticText(win, -1, 'Output files')
		sizer.Add(text2, flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)

		self.output_file_list = wx.ListView(win, -1, size=wx.Size(490, 150), style=wx.LC_REPORT  | wx.RAISED_BORDER)
		self.output_file_list.InsertColumn(0,'Remote path (relative)', width=245)		
		self.output_file_list.InsertColumn(1,'Local path', width=245)	
		sizer.Add(self.output_file_list,flag=wx.EXPAND| wx.ALL | wx.ALIGN_RIGHT, border=5)
		# output file buttons		
		box2 = wx.BoxSizer(wx.HORIZONTAL)		
		self.add_output = wx.Button(win, -1, 'Add...')		
		self.add_output.Bind(wx.EVT_BUTTON, lambda event:self.add_output_file(win,obj))		

		self.rem_output = wx.Button(win, -1, 'Remove')		
		self.rem_output.Disable()
		self.rem_output.Bind(wx.EVT_BUTTON, lambda event:self.remove_output_file(win,obj))		

		self.edit_output = wx.Button(win, -1, 'Edit...')	
		self.edit_output.Disable()		
		self.edit_output.Bind(wx.EVT_BUTTON, lambda event:self.edit_output_file(win,obj))

		box2.Add(self.add_output, flag=wx.ALL, border=5)	
		box2.Add(self.rem_output, flag=wx.ALL, border=5 )	
		box2.Add(self.edit_output, flag=wx.ALL, border=5 )		
		sizer.Add(box2, flag=wx.ALIGN_RIGHT)

		self.output_file_list.Bind(wx.EVT_LIST_ITEM_SELECTED, lambda event:self.output_item_selected(frame, event))
		self.output_file_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, lambda event:self.output_item_deselected(frame, event))	


		self.populate_lists(obj)		

		box3 = wx.BoxSizer(wx.HORIZONTAL)
		buttonOk = wx.Button(win, wx.ID_OK, 'Close', size=(90, 28))
		box3.Add(buttonOk, flag=wx.ALL, border=5)
		sizer.Add(box3,flag=wx.ALIGN_RIGHT)		

		win.SetSizer(sizer)
		win.SetAutoLayout(True)
		dialog.Centre()			
		dialog.ShowModal()
		dialog.Destroy()
		self._save_pref()		
			
	def add_input_file(self,frame,obj):
		local_path, remote_path = self.add_or_edit_file(frame)
		if remote_path != '':
			if obj.plugin_tags.has_key('inputFiles'):
				obj.plugin_tags['inputFiles'].append((local_path,remote_path))
			else:
				obj.plugin_tags['inputFiles'] = [(local_path, remote_path)]
			self.populate_lists(obj)
				
	def edit_input_file(self, frame,obj):
		itemIndex = self.input_file_list.GetFocusedItem()
		local_path, remote_path = obj.plugin_tags['inputFiles'][itemIndex]
 		obj.plugin_tags['inputFiles'][itemIndex] = self.add_or_edit_file(frame,local_path, remote_path)
		self.populate_lists(obj)
			
	def remove_input_file(self,frame,obj):
		dialog = wx.MessageDialog(frame,'Do you really want to remove the selected input file entry?','Remove Input File', wx.ICON_QUESTION | wx.YES_NO)
		if dialog.ShowModal() == wx.ID_YES:
			itemIndex = self.input_file_list.GetFocusedItem()
			del obj.plugin_tags['inputFiles'][itemIndex]
			self.populate_lists(obj)
		
	def add_output_file(self,frame,obj):
		local_path, remote_path = self.add_or_edit_file(frame, is_output=True)
		if local_path != '' and remote_path != '':
			if obj.plugin_tags.has_key('outputFiles'):
				obj.plugin_tags['outputFiles'].append((local_path,remote_path))
			else:
				obj.plugin_tags['outputFiles'] = [(local_path, remote_path)]
			self.populate_lists(obj)

	def edit_output_file(self,frame,obj):
		itemIndex = self.output_file_list.GetFocusedItem()
		local_path, remote_path = obj.plugin_tags['outputFiles'][itemIndex]
 		obj.plugin_tags['outputFiles'][itemIndex] = self.add_or_edit_file(frame,local_path, remote_path, is_output=True)
		self.populate_lists(obj)
	

	def remove_output_file(self,frame,obj):
		dialog = wx.MessageDialog(frame,'Do you really want to remove the selected output file entry?','Remove Output File', wx.ICON_QUESTION | wx.YES_NO)
		if dialog.ShowModal() == wx.ID_YES:		
			itemIndex = self.output_file_list.GetFocusedItem()
			del obj.plugin_tags['outputFiles'][itemIndex]
			self.populate_lists(obj)
		
	def input_item_selected(self,frame, event):
		self.rem_input.Enable()
		self.edit_input.Enable()	

	def input_item_deselected(self,frame, event):
		self.rem_input.Disable()
		self.edit_input.Disable()	
		
	def output_item_selected(self,frame, event):
		self.rem_output.Enable()
		self.edit_output.Enable()	

	def output_item_deselected(self,frame, event):
		self.rem_output.Disable()
		self.edit_output.Disable()	

	def populate_lists(self,obj):
		self.input_file_list.DeleteAllItems()
		idx = 0
		if obj.plugin_tags.has_key('inputFiles'):
			for (local,remote) in obj.plugin_tags['inputFiles']:
				index = self.input_file_list.InsertStringItem(idx,local)
				self.input_file_list.SetStringItem(index,1,remote)	
				idx+=1
		self.output_file_list.DeleteAllItems()
		idx = 0
		if obj.plugin_tags.has_key('outputFiles'):
			for (local,remote) in obj.plugin_tags['outputFiles']:
				index = self.output_file_list.InsertStringItem(idx,remote)
				self.output_file_list.SetStringItem(index,1,local)	
				idx+=1
				


	def _draw_forknjoin_selector(self, mainFrame):

		self.panel = wx.Panel(mainFrame.leftPanel, -1)
		sizer = wx.BoxSizer(wx.VERTICAL)

		self.panel.SetAutoLayout(True)
		self.panel.SetSizer(sizer)

		leftSizer = mainFrame.leftPanel.GetSizer()
		leftSizer.Add(self.panel)

		self.switchButton = wx.CheckBox(self.panel, -1, 'Grid Enabled', style=wx.ALIGN_LEFT)
		self.panel.Bind(wx.EVT_CHECKBOX, lambda event:self._forknjoin_checkbox_changed(mainFrame,event), self.switchButton)

		#self.configure_button = wx.Button(self.panel, -1, "Configure Files...", style=wx.ALIGN_LEFT)
		#self.panel.Bind(wx.EVT_BUTTON, lambda event:self.configure_files(mainFrame), self.configure_button)

		sizer.Add(self.switchButton, 0, wx.ALIGN_LEFT | wx.TOP | wx.BOTTOM, 5)
		#sizer.Add(self.configure_button, 0, wx.ALIGN_LEFT | wx.TOP | wx.BOTTOM, 5)


		if (mainFrame.plugin_attr.has_key('forkNJoin') and mainFrame.plugin_attr['forkNJoin'] == 1):
			self.switchButton.SetValue(True)
			#self.configure_button.Enable()
		else:
			self.switchButton.SetValue(False)
			#self.configure_button.Disable()
		
			

	def _forknjoin_checkbox_changed(self, mainFrame, event):
		value = self._check_forkNjoin(self.switchButton.GetValue())
		if value == 1:
			# To be fork n joinable the network must have exactly one ingoing and one outgoing connection
			mainFrame.plugin_attr['forkNJoin'] = 1;
		else:
			mainFrame.plugin_attr['forkNJoin'] = 0;
			
	def _check_forkNjoin(self, val):
		if (val):
			return 1
		else:
			return 0
	

	# TODO add browse... buttons to file and folder fields
	def _prefmenu_activate(self, frame, event):		
		dialog = wx.Dialog(frame, -1, 'Configure grid', size=wx.Size(500, 250), style = wx.DEFAULT_FRAME_STYLE | wx.WANTS_CHARS )
		win = wx.Panel(dialog, -1)
		hbox = wx.BoxSizer(wx.HORIZONTAL)
		gridSizer = wx.FlexGridSizer(rows=7, cols=2, hgap=5, vgap=5)		
		server_text = wx.TextCtrl(win, -1, self.server)
		cert_text =wx.TextCtrl(win, -1, self.cert)
		key_text = wx.TextCtrl(win, -1, self.key)
		vgrid_text = wx.TextCtrl(win, -1, self.vgrid)
		script_path_text = wx.TextCtrl(win, -1, self.mig_script_path)
		passwd_text = wx.TextCtrl(win, -1, self.passwd,style = wx.TE_PASSWORD)			
		gridSizer.Add(wx.StaticText(win,-1, 'Server:'),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add(server_text, 1, wx.EXPAND)
		gridSizer.Add(wx.StaticText(win,-1, 'Certificate:'),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add(cert_text, 1, wx.EXPAND)		
		gridSizer.Add(wx.StaticText(win,-1, 'Keyfile:'),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add(key_text, 1, wx.EXPAND)		
		gridSizer.Add(wx.StaticText(win,-1, 'Vgrid:'),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add(vgrid_text, 1, wx.EXPAND)		
		gridSizer.Add(wx.StaticText(win,-1, 'Path to MiG scripts:'),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add(script_path_text, 1, wx.EXPAND)		
		gridSizer.Add(wx.StaticText(win,-1, 'Password:'),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add(passwd_text, 1, wx.EXPAND)
		gridSizer.Add(wx.StaticText(win,-1, ''),1,wx.ALIGN_CENTER_VERTICAL)
		gridSizer.Add( wx.Button(win, wx.ID_OK, " Ok "), 1, wx.ALIGN_RIGHT)	
		# TODO add cancel button			
		gridSizer.AddGrowableCol(1, 1)
		hbox.Add(gridSizer, 1, wx.ALL | wx.EXPAND, 15)
		win.SetSizer(hbox)
		win.SetAutoLayout(True)
		dialog.Centre()		
		if dialog.ShowModal() == wx.ID_OK:
			self.server = server_text.GetValue()
			self.cert = cert_text.GetValue()
			self.key = key_text.GetValue()
			self.passwd = passwd_text.GetValue()
			self.vgrid = vgrid_text.GetValue()
			self.mig_script_path = script_path_text.GetValue()
		dialog.Destroy()
		self._save_pref()
	
	def _prefmenu(self, frame, menu, menuid):
		menu.Append(menuid, 'Configure Grid')
		frame.Bind(wx.EVT_MENU, lambda event:self._prefmenu_activate(frame,event), id=menuid)
	

	def _save_pref(self):
		f = open(self.miguser_conf, "w")
		if len(self.server) > 0:
			f.write('migserver '+self.server + '\n')
		if len(self.cert) > 0:
			f.write('certfile '+self.cert + '\n')
		if len(self.key) > 0:
			f.write('keyfile '+self.key + '\n')
		if len(self.passwd) > 0:
			f.write('password '+self.passwd + '\n')
		f.close()
		
		f = open(self.migprefs_conf ,"w")
		if len(self.vgrid) > 0:
			f.write('vgrid ' + self.vgrid + '\n')
		if len(self.mig_script_path):
			f.write('mig_script_path ' + self.mig_script_path + '\n')
		f.close()
	def _load_pref(self):
		if os.path.exists(self.miguser_conf):
			f = open(self.miguser_conf,'r')
			for line in f.readlines():
				parts = line.split()
				if len(parts) == 2:
					if parts[0] == 'migserver':
						self.server = parts[1]
					elif parts[0] == 'certfile':
						self.cert = parts[1]
					elif parts[0] == 'keyfile':
						self.key = parts[1]
					elif parts[0] == 'password':
						self.passwd = parts[1]
					else:
						print 'Got unknown setting in \'.miguser.conf\': ' + line
		if os.path.exists(self.migprefs_conf):
			f = open(self.migprefs_conf,'r')
			for line in f.readlines():
				parts = line.split()
				if len(parts) == 2:
					if parts[0] == 'mig_script_path':
						self.mig_script_path = parts[1]
					elif parts[0] == 'vgrid':
						self.vgrid = parts[1]
					else:
						print 'Got unknown setting in \'.migprefs.conf\': ' + line
	
	def _draw_sendtogrid(self, dc, obj, position, selected):
		attr = obj.plugin_attr
		if attr.has_key('sendToGrid') and attr['sendToGrid'] == 1:
			text = 'MiG'
			if obj.plugin_tags.has_key('migJobConfig'):
				if obj.plugin_tags['migJobConfig'].has_key('inOrderJobs') and obj.plugin_tags['migJobConfig']['inOrderJobs'] > 1:
					text += ' x' + obj.plugin_tags['migJobConfig']['inOrderJobs']# + ' jobs)'

			(text_width,text_height,d,el) = dc.GetFullTextExtent(text)
			y_text_start = position.y + obj.size.height
			dc.DrawRoundedRectangle(position.x + 5, y_text_start - 10, text_width + 10, text_height + 10,2)
			dc.DrawText(text, position.x + 10, y_text_start )
	
	

	def createTag(self, node, obj_plugin_tags):
		# Save config
		if obj_plugin_tags.has_key('inputFiles'):
			for local_path, remote_path in obj_plugin_tags['inputFiles']:
				inputFileNode = cspxml.createDom().createElement('inputFile')
				inputFileNode.setAttribute('local_path', local_path)
				inputFileNode.setAttribute('remote_path',  remote_path)
				node.appendChild(inputFileNode)

		if obj_plugin_tags.has_key('outputFiles'):
			for local_path, remote_path in obj_plugin_tags['outputFiles']:
				outputFileNode = cspxml.createDom().createElement('outputFile')
				outputFileNode.setAttribute('local_path', local_path)
				outputFileNode.setAttribute('remote_path',	remote_path)
				node.appendChild(outputFileNode)
				
		if obj_plugin_tags.has_key('migJobConfig'):
			configNode = cspxml.createDom().createElement('migJobConfig')
			for key, val in obj_plugin_tags['migJobConfig'].items():
				configNode.setAttribute(key,val)
			node.appendChild(configNode)
		
		return node


	# we load files into a list of tuples: (local_path, remote_path)
	def load_file_tags(self, node, obj_plugin_tags):
		for child in node.childNodes:
			if (child.nodeName == 'inputFile'):
				att = cspxml.getAttrList(child)
				if obj_plugin_tags.has_key('inputFiles'):
					obj_plugin_tags['inputFiles'].append((att['local_path'], att['remote_path']))
				else:
					obj_plugin_tags['inputFiles'] = [(att['local_path'], att['remote_path'])]
			elif child.nodeName == 'outputFile':
				att = cspxml.getAttrList(child)
				if obj_plugin_tags.has_key('outputFiles'):
					obj_plugin_tags['outputFiles'].append((att['local_path'], att['remote_path']))
				else:
					obj_plugin_tags['outputFiles'] = [(att['local_path'], att['remote_path'])]
			elif child.nodeName == 'migJobConfig':
				att = cspxml.getAttrList(child)
				obj_plugin_tags['migJobConfig'] = att
				
		return obj_plugin_tags

def load(pluginManager):
	p = PluginForkNJoin(pluginManager)
	# SendToGrid
	p.addRightClickElement(location_PROCESS_LINK, p.create_send_to_grid_rcmenu)	
	p.addRightClickElement(location_PROCESS_LINK, p.create_files_rcmenu)		
	p.addRightClickElement(location_PROCESS_LINK, p.create_job_rcmenu)			
	p.addCSPAttribute(node_PROCESS_LINK, 'sendToGrid', int, 0, p._check_sendToGrid)	
	# Fork and Join capability
	p.addLeftBarElement(p._draw_forknjoin_selector)
	p.addCSPTag(node_PROCESS_LINK,p.createTag, p.load_file_tags)
	p.addCSPAttribute(node_PROCESS_CONTAINER, 'forkNJoin', int, 0, p._check_forkNjoin)
	p.addDrawElement(location_PROCESS, 1, p._draw_sendtogrid)
	# Grid..
	p.addPrefMenuElement(p._prefmenu)
	pluginManager.addPlugin(p)
